// Copyright (C) 2022 即时通讯网(52im.net) & Jack Jiang.
// The RainbowChat Project. All rights reserved.
//
// 【本产品为著作权产品，合法授权后请放心使用，禁止外传！】
// 【本次授权给：<广西木子科技有限公司>，授权编号：<NT220402151538>，代码指纹：<A.648883738.885>，技术对接人微信：<ID: Lingmuziyi>】
// 【授权寄送：<收件：李先生、地址：南宁市科园西十路11号国电智能大厦1101F、电话：17736659550、邮箱：yingshashou@vip.qq.com>】
//
// 【本系列产品在国家版权局的著作权登记信息如下】：
// 1）国家版权局登记名(简称)和权证号：RainbowChat    （证书号：软著登字第1220494号、登记号：2016SR041877）
// 2）国家版权局登记名(简称)和权证号：RainbowChat-Web（证书号：软著登字第3743440号、登记号：2019SR0322683）
// 3）国家版权局登记名(简称)和权证号：RainbowAV      （证书号：软著登字第2262004号、登记号：2017SR676720）
// 4）国家版权局登记名(简称)和权证号：MobileIMSDK-Web（证书号：软著登字第2262073号、登记号：2017SR676789）
// 5）国家版权局登记名(简称)和权证号：MobileIMSDK    （证书号：软著登字第1220581号、登记号：2016SR041964）
// * 著作权所有人：江顺/苏州网际时代信息科技有限公司
//
// 【违法或违规使用投诉和举报方式】：
// 联系邮件：jack.jiang@52im.net
// 联系微信：hellojackjiang
// 联系QQ号：413980957
// 授权说明：http://www.52im.net/thread-1115-1-1.html
// 官方社区：http://www.52im.net
package ws.schild.jave;

import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ScreenExtractor {

    private final static Logger LOG = LoggerFactory.getLogger(ScreenExtractor.class);

    /**
     * The locator of the ffmpeg executable used by this extractor.
     */
    private final FFMPEGLocator locator;
    private int numberOfScreens;

    /**
     * It builds an extractor using a {@link DefaultFFMPEGLocator} instance to
     * locate the ffmpeg executable to use.
     */
    public ScreenExtractor() {
        this.locator = new DefaultFFMPEGLocator();
    }

    /**
     * @return The number of screens found
     */
    public int getNumberOfScreens() {
        return numberOfScreens;
    }

    /**
     * It builds an extractor with a custom {@link FFMPEGLocator}.
     *
     * @param locator The locator picking up the ffmpeg executable used by the
     *                extractor.
     */
    public ScreenExtractor(FFMPEGLocator locator) {
        this.locator = locator;
    }

    /**
     * Generates screenshots from source video.
     *
     * @param multimediaObject Source MultimediaObject @see MultimediaObject
     * @param width            Output width
     * @param height           Output height
     * @param seconds          Interval in seconds between screens
     * @param outputDir        Destination of output images
     * @param fileNamePrefix   Name all thumbnails will start with
     * @param extension        Image extension for output (jpg, png, etc)
     * @param quality          The range is between 1-31 with 31 being the worst quality
     * @throws InputFormatException If the source multimedia file cannot be
     *                              decoded.
     * @throws EncoderException     If a problems occurs during the encoding
     *                              process.
     */
    public void render(MultimediaObject multimediaObject, int width, int height, int seconds, File outputDir,
                       String fileNamePrefix, String extension, int quality)
            throws InputFormatException, EncoderException {
        File inputFile = multimediaObject.getFile();
        try {
            if (!outputDir.exists()) {
                if (!outputDir.mkdirs()) {
                    LOG.debug("Failed to create destination folder");
                    throw new SecurityException();
                }
            }
            if (!inputFile.canRead()) {
                LOG.debug("Failed to open input file");
                throw new SecurityException();
            }
        } catch (SecurityException e) {
            LOG.debug("Access denied checking destination folder" + e);
        }

        MultimediaInfo multimediaInfo = multimediaObject.getInfo();
        numberOfScreens = (int) Math.ceil((multimediaInfo.getDuration() * .001) / seconds + 1);

        FFMPEGExecutor ffmpeg = this.locator.createExecutor();
        ffmpeg.addArgument("-i");
        ffmpeg.addArgument(inputFile.getAbsolutePath());
        ffmpeg.addArgument("-f");
        ffmpeg.addArgument("image2");
        ffmpeg.addArgument("-vf");
        ffmpeg.addArgument(String.format("fps=fps=1/%s", String.valueOf(seconds)));
        ffmpeg.addArgument("-s");
        ffmpeg.addArgument(String.format("%sx%s", String.valueOf(width), String.valueOf(height)));
        ffmpeg.addArgument("-qscale");
        ffmpeg.addArgument(String.valueOf(quality));
        ffmpeg.addArgument(String.format("%s%s%s-%%04d.%s",
                outputDir.getAbsolutePath(), File.separator, fileNamePrefix, extension));

        try {
            ffmpeg.execute();
        } catch (IOException e) {
            throw new EncoderException(e);
        }
        try {
            RBufferedReader reader = new RBufferedReader(
                    new InputStreamReader(ffmpeg.getErrorStream()));
            int step = 0;
            int lineNR = 0;
            String line;
            while ((line = reader.readLine()) != null) {
                lineNR++;
                LOG.debug("Input Line (" + lineNR + "): " + line);
                // TODO: Implement additional input stream parsing
            }
        } catch (IOException e) {
            throw new EncoderException(e);
        } finally {
            ffmpeg.destroy();
        }

    }

    /**
     * Generate a single screenshot from source video.
     *
     * @param multimediaObject Source MultimediaObject @see MultimediaObject
     * @param width            Output width
     * @param height           Output height
     * @param seconds          Interval in seconds between screens
     * @param target           Destination of output image
     * @param quality          The range is between 1-31 with 31 being the worst quality
     * @throws InputFormatException If the source multimedia file cannot be
     *                              decoded.
     * @throws EncoderException     If a problems occurs during the encoding
     *                              process.
     */
    public void render(MultimediaObject multimediaObject, int width, int height, int seconds, File target, int quality)
            throws EncoderException {
        File inputFile = multimediaObject.getFile();
        target = target.getAbsoluteFile();
        target.getParentFile().mkdirs();
        try {
            if (!inputFile.canRead()) {
                LOG.debug("Failed to open input file");
                throw new SecurityException();
            }
        } catch (SecurityException e) {
            LOG.debug("Access denied checking destination folder" + e);
        }

        MultimediaInfo multimediaInfo = multimediaObject.getInfo();
        int duration = (int) (multimediaInfo.getDuration() * .001);
        numberOfScreens = seconds <= duration ? 1 : 0;

        FFMPEGExecutor ffmpeg = this.locator.createExecutor();
        ffmpeg.addArgument("-i");
        ffmpeg.addArgument(inputFile.getAbsolutePath());
        ffmpeg.addArgument("-f");
        ffmpeg.addArgument("image2");
        ffmpeg.addArgument("-vframes");
        ffmpeg.addArgument("1");
        ffmpeg.addArgument("-ss");
        ffmpeg.addArgument(String.valueOf(seconds));
        ffmpeg.addArgument("-s");
        ffmpeg.addArgument(String.format("%sx%s", String.valueOf(width), String.valueOf(height)));
        ffmpeg.addArgument("-qscale");
        ffmpeg.addArgument(String.valueOf(quality));
        ffmpeg.addArgument(target.getAbsolutePath());

        try {
            ffmpeg.execute();
        } catch (IOException e) {
            throw new EncoderException(e);
        }
        try {
            RBufferedReader reader = new RBufferedReader(
                    new InputStreamReader(ffmpeg.getErrorStream()));
            int step = 0;
            int lineNR = 0;
            String line;
            while ((line = reader.readLine()) != null) {
                lineNR++;
                LOG.debug("Input Line (" + lineNR + "): " + line);
                // TODO: Implement additional input stream parsing
            }
        } catch (IOException e) {
            throw new EncoderException(e);
        } finally {
            ffmpeg.destroy();
        }

    }

}
